package com.yonyou.isv.demo.openapi.api;

import com.alibaba.fastjson.JSON;
import com.yonyou.isv.demo.openapi.base.properties.OpenApiProperties;
import com.yonyou.isv.demo.openapi.base.datacenter.DataCenterUrlProvider;
import com.yonyou.isv.demo.openapi.base.exception.BusinessException;
import com.yonyou.isv.demo.openapi.base.module.auth.OpenApiAuthProviderFactory;
import com.yonyou.isv.demo.openapi.base.module.common.OpenApiAccessToken;
import com.yonyou.isv.demo.openapi.base.response.OpenApiResponse;
import com.yonyou.isv.demo.openapi.utils.ReSubmitUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * @description: 开放平台接口调用工具类
 * @author: nishch
 * @create: 2021-07-05
 **/
@Slf4j
@Component
public class BaseOpenApi{

    @Resource
    OpenApiAuthProviderFactory authProvider;
    @Resource
    @Getter
    RestTemplate restTemplate;
    @Resource
    @Getter
    OpenApiProperties properties;
    @Resource
    DataCenterUrlProvider  dataCenterUrlProvider;

    private static String baseFilePath = "src/main/resources/file/";

    public <T> T getForEntity(String urlFragment, Map<String,String> params,Class<T> responseType) {
        String  reqUrl = buildGetRequestUrl(urlFragment,params);
        ResponseEntity<T> responseEntity = restTemplate.getForEntity(reqUrl, responseType);
        return responseEntity.getBody();
    }



    /**
     *
     * @param urlFragment
     * @param params
     * @param responseType
     * @param isEnableResubmit  是否启用幂等
     * @param <T>
     * @return
     */
    public <T> T postForEntity(String urlFragment, Object params,Class<T> responseType,boolean isEnableResubmit) {
        if(isEnableResubmit){
            params = ReSubmitUtil.resubmitCheckKey(params);
        }
        return postForEntity(urlFragment, params,responseType);
    }

    public <T> T postForEntity(String urlFragment, Map<String,String> headers,Object params,Class<T> responseType) {
        String  reqUrl = buildGetRequestUrl(urlFragment,headers);
        if(params!=null)log.info("用友开放平台接口请求参数:"+ JSON.toJSON(params).toString());
        ResponseEntity<T> responseEntity = restTemplate.postForEntity(reqUrl,params,responseType);
        return responseEntity.getBody();
    }

    public <T> T postForEntity(String urlFragment, Object params,Class<T> responseType) {
        String  reqUrl = buildPostRequestUrl(urlFragment);
        if(params!=null)log.info("用友开放平台接口请求参数:"+ JSON.toJSON(params).toString());
        ResponseEntity<T> responseEntity = restTemplate.postForEntity(reqUrl,params,responseType);
        return responseEntity.getBody();
    }

    public <T> T postForEntityUrl(String reqUrl, Object params,Class<T> responseType) {
        ResponseEntity<T> responseEntity = restTemplate.postForEntity(reqUrl,params,responseType);
        return responseEntity.getBody();
    }

    public <T> T getData(OpenApiResponse<T> body){
        if (body == null) {
            throw new BusinessException("unexpected response null when request open api isv access token");
        }
        body.check();
        log.info(JSON.toJSONString(body));
        return body.getData();
    }

    protected String buildPostRequestUrl(String urlFragment) {
        String host = dataCenterUrlProvider.buildBusinessUrl();
        Map<String,String> params = new HashMap<String, String>();
        params.put("access_token", getISVAccessToken().getAccessToken());
        String url = properties.concatParam(host+urlFragment,  properties.buildQueryString(params, false));
        log.info("用友开放平台接口请求:"+url);
        return url;
    }

    protected String buildGetRequestUrl(String urlFragment,Map<String,String> params){
        if(MapUtils.isEmpty(params)){
            return buildPostRequestUrl(urlFragment);
        }
        return properties.concatURL(buildPostRequestUrl(urlFragment), "&", properties.buildQueryString(params, false));
    }

    protected OpenApiAccessToken getISVAccessToken(){
        return authProvider.getAuthProvider().buildISVAuthToken();
    }

    public <T> T file(String urlFragment,String filePath,Map<String,String> header,Class<T> responseType){
        String  reqUrl = buildGetRequestUrl(urlFragment,header);
        //设置请求头
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("multipart/form-data");
        headers.setContentType(type);

        //设置请求体，注意是LinkedMultiValueMap
        String path = new ClassPathResource(baseFilePath+filePath).getPath();
        FileSystemResource fileSystemResource = new FileSystemResource(path);
        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
        form.add("files", fileSystemResource);
        //用HttpEntity封装整个请求报文
        HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<>(form, headers);
        return restTemplate.postForObject(reqUrl, files, responseType);
    }

    /**
     * 请求体包含文件参数和业务参数
     * @author jiaogjin
     * @date 2022/4/26 16:53
     * @return null
     */
    public <T> T fileForPost(String urlFragment,MultiValueMap<String, Object> multimValueMap,Class<T> responseType){
        String  reqUrl = buildPostRequestUrl(urlFragment);
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("multipart/form-data");
        headers.setContentType(type);
        HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<MultiValueMap<String, Object>>(multimValueMap,headers);
        return restTemplate.postForObject(reqUrl, files, responseType);
    }

}
